package svm;

import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import utils.Logger;
import utils.Utils;
import au.AU.Label;
import exception.SessionDirectoryNotFoundException;

/**
 * Object representation of text file created by method
 * Utils.createLuxandData
 */
public class Session implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private File luxandDataFile;
	private String sessionName;
	private List<SessionFrame> sessionFrameList = new ArrayList<SessionFrame>();
	private List<Activity> activityList = new ArrayList<Activity>();

	private List<Interval> intervals;

	// Public API

	/**
	 * Constructor - loads the content of the input Luxand text file.
	 */
	Session(String luxandDataFilePath, HashMap<String, String> keywords, SvmContext c) throws SessionDirectoryNotFoundException {
		this.luxandDataFile = new File(luxandDataFilePath);
		this.sessionName = new File(luxandDataFile.getParent()).getName();
		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader(this.luxandDataFile));
			String line;
			// reading the file line by line
			while ((line = br.readLine()) != null) {
				/*
				 * Columns: [0] - image file name [1] - coordinates of 66 points
				 * [2] - AUs present in the image
				 */
				String[] columns = line.split(":");

				// parsing the points and adding into point list
				List<Point> points = new ArrayList<Point>();
				for (String point : columns[1].split(";")) {
					point = point.replace("[", "");
					point = point.replace("]", "");
					points.add(new Point(Integer.parseInt(point.split(",")[0]),
							Integer.parseInt(point.split(",")[1])));
				}

				// parsing the aus and adding into au list
				List<String> auLabels = new ArrayList<String>();
				if (columns.length > 2) {
					for (String auLabel : columns[2].split(";")) {
						auLabels.add(auLabel);
					}
				}

				// adding a new row to luxand data
				this.sessionFrameList.add(new SessionFrame(columns[0], points,
						auLabels));
			}
			br.close();
		} catch (FileNotFoundException e) {
			Logger.log("Loading Luxand data", "File " + luxandDataFile.getAbsolutePath() + " not found.");
			throw new SessionDirectoryNotFoundException();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		if(keywords != null)
			loadActivities(keywords, c);
				
	}
	
	/**
	 * Loading activities
	 * This is looking for a text file named 'activities' in context parentDir
	 * Parses rows by sessionName
	 * @param keywords: key is a regex that is the activity file line being matched for, value is the humanized name of the activity
	 */
	private void loadActivities(HashMap<String, String> keywords, SvmContext c) {
		String trace = Utils.runCmd("grep " + sessionName + " " + c.parentDir.getAbsolutePath() + "/activities");
		Set<String> keys = keywords.keySet();
		Pattern r;
		Matcher m;
		for(String line: trace.split("\n")) {
			for(Object key: keys.toArray()) {
			    r = Pattern.compile(key.toString());
			    m = r.matcher(line);
				//if(line.contains(key.toString())) {
				if (m.find()) {
					this.activityList.add(new Activity(keywords.get(key.toString()), line));
				}
			}
		}
	}

	public List<Interval> getIntervals() {
		return intervals;
	}

	public void setIntervals(List<Interval> intervals) {
		this.intervals = intervals;
	}
	
	public List<SessionFrame> getSessionFrames() {
		return sessionFrameList;
	}
	
	public List<Activity> getActivityList() {
		return activityList;
	}

	public File getLuxandDataFile() {
		return luxandDataFile;
	}
	
	@Override
	public String toString() {
		return new String("Session: " + sessionName + "; " + sessionFrameList.size() + " rows");
	}
	
	public String toStringWithRows() {
		String res = this.toString();
		for(SessionFrame row: sessionFrameList) if(this.isRecognized() || row.trainingAuLabels.size() > 0) res += "\r\t" + row.toString();
		return res;
	}
	
	public String toStringWithIntervals() {
		String res = this.toString();
		if(this.intervals != null && this.intervals.size() > 0)
			for(Interval interval: intervals) 
				res += "\r\t" + interval.toString();
		return res;
	}
	
	public String toStringWithActivities() {
		String res = this.toString();
		if(this.activityList != null && this.activityList.size() > 0)
			for(Activity act: activityList) 
				res += "\r\t" + act.toString();
		return res;
	}

	/**
	 * One row of the list
	 */
	public class SessionFrame implements Serializable {

		private static final long serialVersionUID = 1L;
		
		public final String fileName;
		public final List<Point> points;
		public final List<String> trainingAuLabels;
		public Date time;
		private HashMap<Label, Double> recognizedAus = new HashMap<Label, Double>();

		public SessionFrame(String fileName, List<Point> points,
				List<String> auLabelList) {
			this.trainingAuLabels = auLabelList;
			this.points = points;
			this.fileName = fileName;
//			String str = fileName.replaceAll("_", "").replaceAll("-", "").replaceAll("\\.", "").replaceAll("jpg", "").replaceAll("png", "");
//			this.time = str;
			try {
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
				Date d;
				d = df.parse(fileName.split("_")[0] + "_" + fileName.split("_")[1]);
				Long tmpTime = d.getTime();
				tmpTime +=(0*60*60*1000);
				time = new Date(tmpTime);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		public void putRecognizedAU(Label label, double level) {
			this.recognizedAus.put(label, level);
		}
		
		public double getRecognizedAU(Label label) {
			if(this.recognizedAus.containsKey(label)) return this.recognizedAus.get(label);
			return 0;
		}
		
		@Override
		public String toString() {
			return new String(
					fileName + " (" + time + ")" + 
					"; " + 
					"Training AUs " + trainingAuLabels.toString() + "; " + 
					"Recognized AUs " + recognizedAus.toString()
				);
		}
	}
	
	public class Activity implements Serializable {
		private static final long serialVersionUID = 1L;
		public Date time;
		public final String name;
		
		public Activity(String name, String line) {
			this.name = name;
			try {
				SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
				Date d;
				d = df.parse(line.split(";")[0]);
				Long tmpTime = d.getTime();
				tmpTime +=(0*60*60*1000);
				time = new Date(tmpTime);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		@Override
		public String toString() {
			return new String("Activity: " + name + ", " + time);
		}
		
	}

	public String getSessionName() {
		return this.sessionName;
	}

	public boolean isRecognized() {
		if(this.sessionFrameList.get(0).recognizedAus.size() > 0) return true;
		return false;
	}
}